'use strict';

const util = require('util')
const limit = process.env.NODE_ENV === 'test' ? 1 : 50

module.exports = {
    classMethods: {
        $countById(id) {
            return this.count({
                where: { id }
            })
        },

        $create(data, condition = {}) {
            return this.create(data, condition)
        },

        $find(condition) {
            return this.find(condition)
        },

        $findAll(condition) {
            return this.findAll(condition)
        },

        $findById(id, condition) {
            return this.findById(id, condition)
        },

        async $pagination(pagination, condition = {}) {
            pagination.count = await this.count({
                where: condition.where,
                include: condition.include ?
                    condition.include.reduce(function(result, model) {
                        if (model.where) {
                            result.push(model)
                        }
                        return result
                    }, []) : null
            })

            condition.limit = pagination.limit

            if (pagination.offset) {
                condition.offset = pagination.offset
            } else if (pagination.after) {
                if (!condition.where) {
                    condition.where = {}
                }

                condition.where.id = {
                    $gt: pagination.after
                }

                condition.order = [
                    ['id', 'ASC']
                ]

            } else if (pagination.before) {
                if (!condition.where) {
                    condition.where = {}
                }

                condition.where.id = {
                    $lt: pagination.before
                }
                condition.order = [
                    ['id', 'DESC']
                ]
            }

            const result = await this.findAll(condition)
            return Promise.resolve(result)
        },

        $update(id, data, condition) {
            return this.update(data, { where: { id } }, condition)
        },

        $destroy(id, deleteBy) {
            return this.destroy({ where: { id } }, { deleteBy })
        },

        $delete(where) {
            return this.destroy({ where })
        },

        async $batch($in, condition = {}) {

            if (!condition.where) condition.where = {}
            condition.where.id = { $in }

            const raw = await this.findAll(condition)

            const map = raw.reduce(function(result, item) {
                result[item.id] = item
                return result
            }, {})

            const data = $in.reduce(function(result, id) {
                result.push(map[id] || null)
                return result
            }, [])

            return data
        },

        $search(fields, keyword, condition = {}) {
            const $like = `%${keyword}%`

            if (!condition.where) condition.where = {}

            condition.limit = limit

            if (util.isArray(fields)) {
                condition.where.$or = fields.reduce(function(result, field) {
                    result.push({
                        [field]: { $like }
                    })
                    return result
                }, [])
            } else {
                condition.where[fields] = { $like }
            }

            return this.findAll(condition)
        }
    }
}